package com.cib.xagcjs.utils;

import com.alibaba.fastjson.JSONObject;
import com.cib.xagcjs.config.KeyConfig;
import com.cib.xagcjs.utils.gm.SM2Utils;
import com.cib.xagcjs.utils.gm.SM4Utils;
import com.cib.xagcjs.utils.gm.Util;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Configurable;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.UUID;

/**
 * Description: 加密和解密的工具方法
 * Author: jingcaiqi1225@gmail.com
 * Date: 2024/1/31 11:26
 */
@Slf4j
@Component
public class CryptoUtils {

    @Autowired
    private KeyConfig keyConfig;

    /**
     * 解密方法
     * @param message 经过加密的数据
     * @return 解密后的数据
     */
    public String decryptAndVerify(String message) {
        try {

            JSONObject jsonObj = JSONObject.parseObject(message);
            String data = jsonObj.getString("data");
            String sign = jsonObj.getString("sign");
            String key = jsonObj.getString("key");

            byte[] sessionKey = SM2Utils.decrypt(Util.hexToByte(keyConfig.getPriK()), Util.hexToByte(key));
            byte[] mes = SM4Utils.decryptData_ECB(Util.hexToByte(data), sessionKey);
            boolean flag = SM2Utils.verifySign("".getBytes(), Util.hexToByte(keyConfig.getPubK()), mes, Util.hexToByte(sign));

            if (flag) {
                String s = new String(mes, "GBK");
                log.info("解密和验证成功:" + s);
                return s;
            } else {
                return "验证失败";
            }
        } catch (Exception e) {
            return "解密和验证过程发生异常: " + e.getMessage();
        }
    }

    /**
     * 加密方法
     * @param message 需要加密数据
     * @return 加密后的数据
     */
    public String encryptAndSign(String message) throws Exception {

        String sessionKey = UUID.randomUUID().toString().replaceAll("-", "");	// 随机秘钥

        // 使用 SM4 算法对消息进行 ECB 模式的对称加密，使用 sessionKey 作为密钥 （data是加密后的数据）
        String data = Util.byteToHex(SM4Utils.encryptData_ECB(message.getBytes("GBK"), sessionKey.getBytes()));
        // 使用 SM2 算法对消息进行数字签名，使用客户端的私钥 priK （sign是加密后的数字签名）
        String sign = Util.byteToHex(SM2Utils.sign("".getBytes(), Util.hexToByte(keyConfig.getPriK()), message.getBytes("GBK")));
        // 使用 SM2 算法对 sessionKey 进行加密，使用服务端的公钥 pubKey
        String key = Util.byteToHex(SM2Utils.encrypt(Util.hexToByte(keyConfig.getPubK()), sessionKey.getBytes()));
        // 将加密后的数据、数字签名、以及密钥加密后的 sessionKey 构建成一个 JSON 对象
        JSONObject jsonObj = new JSONObject();
        jsonObj.put("data", data);
        jsonObj.put("sign", sign);
        jsonObj.put("key", key);
        //总体思路是，客户端使用对称加密算法 SM4 对消息进行加密，同时使用非对称加密算法 SM2 对消息进行数字签名。
        // 然后，将加密后的数据、数字签名、以及密钥加密后的 sessionKey 作为请求报文发送到服务端。
        // 服务端可以使用对应的私钥解密密文，验证数字签名，并使用解密后的 sessionKey 解密对称加密的数据。

        log.info("发送报文加密后打印:" + jsonObj.toJSONString());
        return jsonObj.toJSONString();
    }
}
